package main

import (
	"log"
	"strconv"
	"sync"
	"time"

	"client2/config"
	"client2/mqtt"
	"client2/sensor"
	"client2/web_http"
	"client2/zkp"
)

func main() {
	log.Println("=== 启动客户端 ===")

	// 从device_config.json加载配置
	cfg := config.LoadConfigFromDeviceConfig()
	BASE_URL := cfg.Server.BaseURL

	// 初始化 ZKP 密钥管理器
	log.Println("初始化 ZKP 密钥管理器...")
	keyManager, err := zkp.NewKeyManager()
	if err != nil {
		log.Fatalf("初始化 ZKP 密钥管理器失败: %v", err)
	}
	prover := keyManager.GetProver()
	log.Println("ZKP 密钥管理器初始化完成")

	// 创建传感器管理器（只初始化，不运行读取循环）
	sensorManager := sensor.NewSensorManager(cfg)
	defer sensorManager.Close()

	// ✅ 修复：加载所有传感器设备配置
	log.Println("加载传感器设备配置...")
	sensorConfigs := config.LoadSensorDeviceConfigs()
	if len(sensorConfigs) == 0 {
		log.Fatal("没有配置任何传感器设备")
	}
	log.Printf("加载了 %d 个传感器设备配置", len(sensorConfigs))

	// 打印所有传感器配置
	for i, cfg := range sensorConfigs {
		log.Printf("  传感器 %d: ID=%s, Type=%s, Registered=%v",
			i+1, cfg.DeviceID, cfg.SensorType, cfg.Registered)
	}

	// 健康检查循环（优化：降低检查频率，减少不必要的网络请求）
	go func() {
		// 添加 panic 恢复机制，防止健康检查错误导致程序崩溃
		defer func() {
			if r := recover(); r != nil {
				log.Printf("❌ 健康检查 goroutine 发生 panic: %v", r)
				// 重新启动健康检查 goroutine
				go func() {
					time.Sleep(10 * time.Second) // 等待10秒后重启
					// 这里可以重新启动健康检查，但为了避免无限递归，我们只记录错误
				}()
			}
		}()

		for {
			log.Println("=== 开始健康检查 ===")

			// 健康检查
			healthy, err := web_http.CheckServerHealth(BASE_URL)
			if err != nil {
				log.Printf("⚠️  健康检查失败: %v", err)
			} else {
				log.Printf("✅ 健康检查结果: %v", healthy)
			}

			// 就绪检查
			ready, err := web_http.CheckServerReadiness(BASE_URL)
			if err != nil {
				log.Printf("⚠️  就绪检查失败: %v", err)
			} else {
				log.Printf("✅ 就绪检查结果: %v", ready)
			}

			log.Println("=== 健康检查完成 ===")
			// 优化：服务端状态稳定，从30秒改为5分钟检查一次
			time.Sleep(5 * time.Minute)
		}
	}()

	// ✅ 修复：为每个设备创建独立的状态管理
	deviceStates := make(map[string]*web_http.DeviceState)
	for i := range sensorConfigs {
		deviceStates[sensorConfigs[i].DeviceID] = &web_http.DeviceState{}
	}

	// 创建配置文件保存的互斥锁（保护并发写入）
	var configMutex sync.Mutex
	saveConfig := func() {
		configMutex.Lock()
		defer configMutex.Unlock()
		config.SaveSensorDeviceConfigs(sensorConfigs)
	}

	// ✅ 修复：异步检查和注册所有设备
	go func() {
		// 添加 panic 恢复机制，防止设备注册错误导致程序崩溃
		defer func() {
			if r := recover(); r != nil {
				log.Printf("❌ 设备注册 goroutine 发生 panic: %v", r)
			}
		}()

		log.Println("=== 开始设备注册流程 ===")

		// 遍历所有传感器配置
		for i := range sensorConfigs {
			sensorConfig := &sensorConfigs[i]

			log.Printf("检查设备 %s 是否已在服务端注册...", sensorConfig.DeviceID)
			exists, err := web_http.CheckDeviceExists(sensorConfig.DeviceID, BASE_URL)
			if err != nil {
				log.Printf("[%s] 检查设备存在性失败: %v", sensorConfig.DeviceID, err)
				continue
			}

			// ✅ 修复：检查本地 commitment 是否为空，如果为空则需要重新注册
			needRegister := !exists || sensorConfig.Commitment == ""

			if needRegister {
				if !exists {
					log.Printf("[%s] 设备在服务端不存在，需要注册", sensorConfig.DeviceID)
				} else if sensorConfig.Commitment == "" {
					log.Printf("[%s] 本地 commitment 为空，需要重新注册更新 commitment", sensorConfig.DeviceID)
				}
				sensorConfig.Registered = false

				// 注册设备
				log.Printf("[%s] 开始注册设备...", sensorConfig.DeviceID)
				if err := web_http.RegisterDevice(sensorConfig, BASE_URL); err != nil {
					log.Printf("[%s] ❌ 设备注册失败: %v", sensorConfig.DeviceID, err)
					continue
				}
				log.Printf("[%s] ✅ 设备注册成功! Commitment: %s", sensorConfig.DeviceID, sensorConfig.Commitment)
			} else {
				log.Printf("[%s] 设备已在服务端注册且本地 commitment 已存在，跳过注册流程", sensorConfig.DeviceID)
				sensorConfig.Registered = true
			}
		}

		// 保存更新后的配置
		log.Println("保存更新后的传感器配置...")
		saveConfig()

		log.Println("=== 设备注册流程完成 ===")

		// ✅ 修复：为每个设备启动独立的认证循环
		log.Println("=== 启动所有设备的认证流程 ===")
		for i := range sensorConfigs {
			sensorConfig := &sensorConfigs[i]
			deviceState := deviceStates[sensorConfig.DeviceID]

			// 每个设备在独立的goroutine中认证，传入保存配置的回调函数
			go web_http.StartAuthentication(sensorConfig, deviceState, BASE_URL, prover, saveConfig)

			// 稍微延迟启动下一个设备的认证，避免同时请求
			time.Sleep(2 * time.Second)
		}
		log.Println("=== 所有设备认证流程已启动 ===")
	}()

	// ✅ 修复：为每个设备创建独立的MQTT客户端
	mqttClients := make(map[string]*mqtt.Client)
	mqttPublishers := make(map[string]*mqtt.Publisher)
	lastTokens := make(map[string]string)

	// 数据发布节流控制：记录每个传感器上次发布的时间和数据
	type SensorPublishState struct {
		LastPublishTime time.Time
		LastValue       interface{}
	}
	sensorPublishStates := make(map[string]*SensorPublishState)
	for _, sensorConfig := range sensorConfigs {
		sensorPublishStates[sensorConfig.DeviceID] = &SensorPublishState{
			LastPublishTime: time.Time{}, // 零值，首次必定发布
		}
	}

	// 发布间隔和变化阈值配置
	const (
		minPublishInterval          = 2 * time.Second  // 最小发布间隔：2秒
		maxPublishInterval          = 60 * time.Second // 最大发布间隔：60秒（心跳机制，防止服务端误判设备离线，与MQTT keepalive一致）
		tempChangeThreshold         = 0.5              // 温度变化阈值：0.5°C
		coChangeThreshold           = 0.1              // CO浓度变化阈值：0.1 MG/M3
		co2ChangeThreshold          = 10.0             // CO2浓度变化阈值：10 ppm
		smokeChangeThreshold        = 10               // 烟雾AD值变化阈值
		conductivityChangeThreshold = 5                // 电导率变化阈值：5 mS/cm
		liquidLevelChangeThreshold  = 10               // 液位数据量变化阈值：5 mm
	)

	// 启动传感器数据读取（在独立goroutine中运行）
	log.Println("启动传感器数据读取...")
	go sensorManager.Run()

	// 确保所有 MQTT 客户端在程序退出时断开
	defer func() {
		for deviceID, client := range mqttClients {
			if client != nil {
				log.Printf("断开设备 %s 的 MQTT 连接...", deviceID)
				client.Disconnect()
			}
		}
	}()

	// 主循环负责保持程序运行和状态监控
	log.Println("进入主监控循环...")
	ticker := time.NewTicker(10 * time.Second)
	defer ticker.Stop()

	// 状态打印控制（优化：只在状态变化或每5分钟时打印）
	var lastValidTokenCount int = -1
	var lastMqttConnectedCount int = -1
	var lastSensorCount int = -1
	lastStatusPrintTime := time.Now()
	statusPrintInterval := 5 * time.Minute // 每5分钟至少打印一次状态摘要

	// 确保 SetDataHandler 只设置一次
	var dataHandlerSet bool

	for range ticker.C {
		// 添加 panic 恢复机制，防止主循环错误导致程序崩溃
		func() {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("❌ 主循环发生 panic: %v", r)
					// 记录堆栈信息以便调试
					log.Printf("主循环 panic 详情: %+v", r)
				}
			}()

			// ✅ 修复：监控所有设备的token状态
			validTokenCount := 0
			for _, sensorConfig := range sensorConfigs {
				deviceState := deviceStates[sensorConfig.DeviceID]

				if deviceState.Token != "" && time.Now().Before(deviceState.TokenExpiry) {
					validTokenCount++

					// 检查是否需要初始化或更新 MQTT 客户端
					if cfg.MQTT.Enabled && (mqttClients[sensorConfig.DeviceID] == nil || lastTokens[sensorConfig.DeviceID] != deviceState.Token) {
						log.Printf("[%s] === 初始化/更新 MQTT 客户端 ===", sensorConfig.DeviceID)

						// 如果已有客户端，先断开
						if mqttClients[sensorConfig.DeviceID] != nil {
							log.Printf("[%s] 断开旧的 MQTT 连接...", sensorConfig.DeviceID)
							mqttClients[sensorConfig.DeviceID].Disconnect()
						}

						// 创建新的 MQTT 客户端
						mqttConfig := &mqtt.Config{
							Broker:   cfg.MQTT.Broker,
							ClientID: sensorConfig.DeviceID,
							Username: cfg.MQTT.Username,
							Password: deviceState.Token, // 使用 JWT token 作为密码
							QoS:      cfg.MQTT.QoS,
							Retained: cfg.MQTT.Retained,
							TLS: &mqtt.TLSConfig{
								Enabled:            cfg.MQTT.TLS.Enabled,
								CAFile:             cfg.MQTT.TLS.CAFile,
								CertFile:           cfg.MQTT.TLS.CertFile,
								KeyFile:            cfg.MQTT.TLS.KeyFile,
								InsecureSkipVerify: cfg.MQTT.TLS.InsecureSkipVerify,
							},
						}

						var err error
						mqttClients[sensorConfig.DeviceID], err = mqtt.NewClient(mqttConfig, deviceState.Token)
						if err != nil {
							log.Printf("[%s] ❌ MQTT 连接失败: %v", sensorConfig.DeviceID, err)
							mqttClients[sensorConfig.DeviceID] = nil
						} else {
							log.Printf("[%s] ✅ MQTT 客户端创建成功", sensorConfig.DeviceID)
							mqttPublishers[sensorConfig.DeviceID] = mqtt.NewPublisher(mqttClients[sensorConfig.DeviceID])
							lastTokens[sensorConfig.DeviceID] = deviceState.Token

							// 发布设备上线状态
							status := &mqtt.DeviceStatus{
								DeviceID:  sensorConfig.DeviceID,
								Status:    "online",
								Timestamp: time.Now(),
								Metadata: map[string]interface{}{
									"mqtt_enabled": true,
									"zkp_auth":     true,
									"sensor_type":  sensorConfig.SensorType,
								},
							}
							if err := mqttPublishers[sensorConfig.DeviceID].PublishDeviceStatus(status); err != nil {
								log.Printf("[%s] 发布设备状态失败: %v", sensorConfig.DeviceID, err)
							}
						}
					}
				}
			}

			// 设置传感器数据处理函数（只设置一次）
			if validTokenCount > 0 && sensorManager != nil && !dataHandlerSet {
				dataHandlerSet = true
				sensorManager.SetDataHandler(func(data sensor.SensorData) {
					// 添加 panic 恢复机制，防止单个传感器数据处理错误导致整个程序崩溃
					defer func() {
						if r := recover(); r != nil {
							log.Printf("[%s] ❌ 处理传感器数据时发生panic: %v", data.SensorID, r)
						}
					}()
					// 根据 sensor_id 找到对应的 publisher
					publisher := mqttPublishers[data.SensorID]
					if publisher == nil {
						return
					}

					// 获取该传感器的发布状态
					publishState := sensorPublishStates[data.SensorID]
					if publishState == nil {
						return
					}

					// 检查是否满足发布条件
					now := time.Now()
					timeSinceLastPublish := now.Sub(publishState.LastPublishTime)

					// 如果距离上次发布时间不足最小间隔，跳过
					if timeSinceLastPublish < minPublishInterval {
						return
					}

					// 检查是否超过最大发布间隔（心跳机制）
					exceededMaxInterval := timeSinceLastPublish >= maxPublishInterval

					// 根据传感器类型处理数据，并检查数据变化
					shouldPublish := false
					var currentValue interface{}

					switch data.SensorType {
					case "temperature_humidity", "temperature":
						// 温度数据
						if tempStr, ok := data.Values["temperature"].(string); ok {
							temp, err := strconv.ParseFloat(tempStr, 64)
							if err == nil {
								currentValue = temp
								// 检查温度变化是否超过阈值
								if publishState.LastValue == nil {
									shouldPublish = true // 首次发布
								} else if lastTemp, ok := publishState.LastValue.(float64); ok {
									if abs(temp-lastTemp) >= tempChangeThreshold {
										shouldPublish = true // 数据变化超过阈值
									}
								}

								// 心跳机制：即使数据未变化，超过最大间隔也要发布
								if !shouldPublish && exceededMaxInterval {
									shouldPublish = true
									log.Printf("[%s] 心跳发布温度数据 (%.2f°C, 距上次发布 %.0f秒)",
										data.SensorID, temp, timeSinceLastPublish.Seconds())
								}

								// 如果需要发布
								if shouldPublish {
									tempData := &mqtt.SensorData{
										DeviceID:   data.SensorID,
										SensorType: "temperature",
										Value:      temp,
										Unit:       "°C",
										Timestamp:  data.Timestamp,
										Quality:    100,
									}
									if err := publisher.PublishSensorData(tempData); err != nil {
										log.Printf("[%s] 发布温度数据失败: %v", data.SensorID, err)
									}
								}
							}
						}

					case "co":
						// CO 浓度数据
						if conc, ok := data.Values["concentration"].(float64); ok {
							currentValue = conc
							// 检查CO浓度变化是否超过阈值
							if publishState.LastValue == nil {
								shouldPublish = true // 首次发布
							} else if lastConc, ok := publishState.LastValue.(float64); ok {
								if abs(conc-lastConc) >= coChangeThreshold {
									shouldPublish = true // 数据变化超过阈值
								}
							}

							// 心跳机制：即使数据未变化，超过最大间隔也要发布
							if !shouldPublish && exceededMaxInterval {
								shouldPublish = true
								log.Printf("[%s] 心跳发布CO数据 (%.2f MG/M3, 距上次发布 %.0f秒)",
									data.SensorID, conc, timeSinceLastPublish.Seconds())
							}

							// 如果需要发布
							if shouldPublish {
								coData := &mqtt.SensorData{
									DeviceID:   data.SensorID,
									SensorType: "co",
									Value:      conc,
									Unit:       "MG/M3",
									Timestamp:  data.Timestamp,
									Quality:    100,
								}
								if err := publisher.PublishSensorData(coData); err != nil {
									log.Printf("[%s] 发布CO数据失败: %v", data.SensorID, err)
								}
							}
						}

					case "co2":
						// CO2 浓度数据
						if conc, ok := data.Values["concentration"].(uint16); ok {
							currentValue = float64(conc)
							// 检查CO2浓度变化是否超过阈值
							if publishState.LastValue == nil {
								shouldPublish = true // 首次发布
							} else if lastConc, ok := publishState.LastValue.(float64); ok {
								if abs(currentValue.(float64)-lastConc) >= co2ChangeThreshold {
									shouldPublish = true // 数据变化超过阈值
								}
							}

							// 心跳机制：即使数据未变化，超过最大间隔也要发布
							if !shouldPublish && exceededMaxInterval {
								shouldPublish = true
								log.Printf("[%s] 心跳发布CO2数据 (%.0f ppm, 距上次发布 %.0f秒)",
									data.SensorID, currentValue.(float64), timeSinceLastPublish.Seconds())
							}

							// 如果需要发布
							if shouldPublish {
								co2Data := &mqtt.SensorData{
									DeviceID:   data.SensorID,
									SensorType: "co2",
									Value:      currentValue.(float64),
									Unit:       "ppm",
									Timestamp:  data.Timestamp,
									Quality:    100,
								}
								if err := publisher.PublishSensorData(co2Data); err != nil {
									log.Printf("[%s] 发布CO2数据失败: %v", data.SensorID, err)
								}
							}
						}

					case "smoke":
						// 烟雾传感器数据
						if adValue, ok := data.Values["ad_value"].(uint16); ok {
							currentValue = float64(adValue)
							// 检查烟雾AD值变化是否超过阈值
							if publishState.LastValue == nil {
								shouldPublish = true // 首次发布
							} else if lastValue, ok := publishState.LastValue.(float64); ok {
								if abs(currentValue.(float64)-lastValue) >= float64(smokeChangeThreshold) {
									shouldPublish = true // 数据变化超过阈值
								}
							}

							// 心跳机制：即使数据未变化，超过最大间隔也要发布
							if !shouldPublish && exceededMaxInterval {
								shouldPublish = true
								log.Printf("[%s] 心跳发布烟雾数据 (AD值:%.0f, 距上次发布 %.0f秒)",
									data.SensorID, currentValue.(float64), timeSinceLastPublish.Seconds())
							}

							// 如果需要发布
							if shouldPublish {
								smokeData := &mqtt.SensorData{
									DeviceID:   data.SensorID,
									SensorType: "smoke",
									Value:      currentValue.(float64),
									Unit:       "AD",
									Timestamp:  data.Timestamp,
									Quality:    100,
									Metadata: map[string]interface{}{
										"full_scale": data.Values["full_scale"],
									},
								}
								if err := publisher.PublishSensorData(smokeData); err != nil {
									log.Printf("[%s] 发布烟雾数据失败: %v", data.SensorID, err)
								}
							}
						}

					case "conductivity":
						// 电导率传感器数据
						if conductivity, ok := data.Values["conductivity"].(uint16); ok {
							currentValue = float64(conductivity)
							// 检查电导率变化是否超过阈值
							if publishState.LastValue == nil {
								shouldPublish = true // 首次发布
							} else if lastValue, ok := publishState.LastValue.(float64); ok {
								if abs(currentValue.(float64)-lastValue) >= float64(conductivityChangeThreshold) {
									shouldPublish = true // 数据变化超过阈值
								}
							}

							// 心跳机制：即使数据未变化，超过最大间隔也要发布
							if !shouldPublish && exceededMaxInterval {
								shouldPublish = true
								log.Printf("[%s] 心跳发布电导率数据 (%.0f mS/cm, 距上次发布 %.0f秒)",
									data.SensorID, currentValue.(float64), timeSinceLastPublish.Seconds())
							}

							// 如果需要发布
							if shouldPublish {
								conductivityData := &mqtt.SensorData{
									DeviceID:   data.SensorID,
									SensorType: "conductivity",
									Value:      currentValue.(float64),
									Unit:       "mS/cm",
									Timestamp:  data.Timestamp,
									Quality:    100,
									Metadata: map[string]interface{}{
										"temperature": data.Values["temperature"],
									},
								}
								if err := publisher.PublishSensorData(conductivityData); err != nil {
									log.Printf("[%s] 发布电导率数据失败: %v", data.SensorID, err)
								}
							}
						}

					case "liquid_level":
						// 液位传感器数据（使用转换后的 mm 值）
						if liquidLevel, ok := data.Values["liquid_level"].(float64); ok {
							currentValue = liquidLevel
							// 检查液位数据变化是否超过阈值（单位：mm）
							if publishState.LastValue == nil {
								shouldPublish = true // 首次发布
							} else if lastValue, ok := publishState.LastValue.(float64); ok {
								if abs(currentValue.(float64)-lastValue) >= float64(liquidLevelChangeThreshold) {
									shouldPublish = true // 数据变化超过阈值
								}
							}

							// 心跳机制：即使数据未变化，超过最大间隔也要发布
							if !shouldPublish && exceededMaxInterval {
								shouldPublish = true
								log.Printf("[%s] 心跳发布液位数据 (%.2f mm, 距上次发布 %.0f秒)",
									data.SensorID, currentValue.(float64), timeSinceLastPublish.Seconds())
							}

							// 如果需要发布
							if shouldPublish {
								liquidLevelData := &mqtt.SensorData{
									DeviceID:   data.SensorID,
									SensorType: "liquid_level",
									Value:      currentValue.(float64),
									Unit:       "mm",
									Timestamp:  data.Timestamp,
									Quality:    100,
								}
								if err := publisher.PublishSensorData(liquidLevelData); err != nil {
									log.Printf("[%s] 发布液位数据失败: %v", data.SensorID, err)
								}
							}
						}

					case "flow":
						// 流速传感器数据（使用转换后的 L/min 值）
						if flowRate, ok := data.Values["flow_rate"].(float64); ok {
							currentValue = flowRate
							// 定义流速变化阈值（单位：L/min）
							flowRateChangeThreshold := 0.5 // 流速变化0.5 L/min触发发布

							// 检查流速数据变化是否超过阈值
							if publishState.LastValue == nil {
								shouldPublish = true // 首次发布
							} else if lastValue, ok := publishState.LastValue.(float64); ok {
								if abs(currentValue.(float64)-lastValue) >= flowRateChangeThreshold {
									shouldPublish = true // 数据变化超过阈值
								}
							}

							// 心跳机制：即使数据未变化，超过最大间隔也要发布
							if !shouldPublish && exceededMaxInterval {
								shouldPublish = true
								log.Printf("[%s] 心跳发布流速数据 (%.2f L/min, 距上次发布 %.0f秒)",
									data.SensorID, currentValue.(float64), timeSinceLastPublish.Seconds())
							}

							// 如果需要发布
							if shouldPublish {
								flowData := &mqtt.SensorData{
									DeviceID:   data.SensorID,
									SensorType: "flow",
									Value:      currentValue.(float64),
									Unit:       "L/min",
									Timestamp:  data.Timestamp,
									Quality:    100,
								}
								if err := publisher.PublishSensorData(flowData); err != nil {
									log.Printf("[%s] 发布流速数据失败: %v", data.SensorID, err)
								}
							}
						}
					}

					// 更新发布状态
					if shouldPublish {
						publishState.LastPublishTime = now
						publishState.LastValue = currentValue
					}
				})
			}

			// 优化：计算当前状态
			currentSensorCount := sensorManager.Get_num()
			mqttConnectedCount := 0
			for _, client := range mqttClients {
				if client != nil {
					mqttConnectedCount++
				}
			}

			// 检测状态是否发生变化
			statusChanged := (validTokenCount != lastValidTokenCount) ||
				(mqttConnectedCount != lastMqttConnectedCount) ||
				(currentSensorCount != lastSensorCount)

			// 是否到了定期打印时间（每5分钟）
			shouldPrintPeriodic := time.Since(lastStatusPrintTime) >= statusPrintInterval

			// 只在状态变化或到达定期打印时间时打印
			if statusChanged || shouldPrintPeriodic {
				log.Println("========================================")
				log.Printf("📊 系统状态摘要")
				log.Printf("  ├─ 有效令牌设备: %d/%d %s",
					validTokenCount, len(sensorConfigs),
					getStatusEmoji(validTokenCount == len(sensorConfigs)))
				log.Printf("  ├─ 活动传感器: %d %s",
					currentSensorCount,
					getStatusEmoji(currentSensorCount == len(sensorConfigs)))
				log.Printf("  └─ MQTT连接: %d/%d %s",
					mqttConnectedCount, len(sensorConfigs),
					getStatusEmoji(mqttConnectedCount == len(sensorConfigs)))

				// 如果是状态变化，额外说明
				if statusChanged && !shouldPrintPeriodic {
					log.Printf("💡 状态已更新 (令牌:%d→%d, MQTT:%d→%d, 传感器:%d→%d)",
						lastValidTokenCount, validTokenCount,
						lastMqttConnectedCount, mqttConnectedCount,
						lastSensorCount, currentSensorCount)
				}
				log.Println("========================================")

				// 更新上次打印的状态和时间
				lastValidTokenCount = validTokenCount
				lastMqttConnectedCount = mqttConnectedCount
				lastSensorCount = currentSensorCount
				lastStatusPrintTime = time.Now()
			}
		}() // 关闭主循环的panic恢复匿名函数
	}
}

// getStatusEmoji 根据状态返回对应的emoji
func getStatusEmoji(isGood bool) string {
	if isGood {
		return "✅"
	}
	return "⚠️"
}

// abs 计算浮点数的绝对值
func abs(x float64) float64 {
	if x < 0 {
		return -x
	}
	return x
}
